﻿#region Using directives

using System;
using System.Collections.Generic;
using System.Text;

#endregion

namespace Weazel.Gezel.Model
{
  public enum TransitionType
  {
    SimpleUnconditional,
    SimpleConditional,
    Nested,
  }

  public class Transition : AbstractEntity<Controller>
  {
    public readonly TransitionType TransitionType;
    
    /// <summary>
    /// Name of the state which is the source of 
    /// this transition
    /// </summary>
    private string sourceState;
		public string SourceState
		{
			get { return sourceState; }
			protected set { sourceState = value; }
		}

    private string firstTargetState;
		public string FirstTargetState
		{
			get { return firstTargetState; }
			protected set { firstTargetState = value; }
		}

    private string[] firstTargetSfgs;
		public string[] FirstTargetSfgs
		{
			get { return firstTargetSfgs; }
			protected set { firstTargetSfgs = value; }
		}

    private string secondTargetState;
		public string SecondTargetState
		{
			get { return secondTargetState; }
			protected set { secondTargetState = value; }
		}

		private string[] secondTargetSfgs;
		public string[] SecondTargetSfgs
		{
			get { return secondTargetSfgs; }
			protected set { secondTargetSfgs = value; }
		}

    private Transition firstTransition;
		public Transition FirstTransition
		{
			get { return firstTransition; }
			protected set { firstTransition = value; }
		}

    private Transition secondTransition;
		public Transition SecondTransition
		{
			get { return secondTransition; }
			protected set { secondTransition = value; }
		}

    private Expression condition;
		public Expression Condition
		{
			get { return condition; }
			protected set { condition = value; }
		}

    public readonly bool TraceFirst;
    public readonly bool TraceSecond;

		protected Transition(Controller parent)
			: base(parent, null)
		{

		}

		public Transition(
			Controller parent, 
			string target, 
			string[] sfgs, 
			bool trace, 
			string sourceState,
			Position startPosition,
			Position endPosition
		) 
			: this(parent, target, sfgs, trace, sourceState)
    {
			this.startPosition = startPosition;
			this.endPosition = endPosition;
    }

    public Transition(Controller parent, string target, string[] sfgs, bool trace, string sourceState) : 
      this(parent, target, sfgs, trace)
    {
      this.SourceState = sourceState;
    }

    public Transition(Controller parent, string target, string[] sfgs, bool trace) : base(parent)
    {
      this.TransitionType = TransitionType.SimpleUnconditional;
      this.FirstTargetState = target;
      this.FirstTargetSfgs = sfgs;
      this.Condition = null;
      this.TraceFirst = trace;
    }

    public Transition(
			Controller parent, 
			Expression condition, 
			Transition first, 
			Transition second, 
			string sourceState,
			Position startPosition,
			Position endPosition
		) 
			: this(parent, condition, first, second, sourceState)
    {
			this.startPosition = startPosition;
			this.endPosition = endPosition;
    }

    public Transition(Controller parent, Expression condition, Transition first, Transition second, string sourceState) : 
      this(parent, condition, first, second)
    {
      this.SourceState = sourceState;
    }

    public Transition(Controller parent, Expression condition, Transition first, Transition second) : base(parent)
    {
      // reduce transition
      if (first.TransitionType == TransitionType.SimpleUnconditional && second.TransitionType == TransitionType.SimpleUnconditional)
      {
        this.TransitionType = TransitionType.SimpleConditional;

        this.FirstTargetSfgs = first.FirstTargetSfgs;
        this.FirstTargetState = first.FirstTargetState;
        this.TraceFirst = first.TraceFirst;

        this.SecondTargetSfgs = second.FirstTargetSfgs;
        this.SecondTargetState = second.FirstTargetState;
        this.TraceSecond = second.TraceFirst;

        this.Condition = condition;
      }
      else // cant reduce child transitions, since they are nested or conditional 
      {
        this.TransitionType = TransitionType.Nested;
        this.FirstTransition = first;
        this.SecondTransition = second;
        this.Condition = condition;
      }
    }
  }
}
